package warmachineroster.service.validation.calculators;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import warmachineroster.Roster;
import warmachineroster.WarcasterRosterElement;
import warmachineroster.service.validation.UnitCounter;
import warmachinesystem.BaseUnit;
import warmachinesystem.TBFieldAllowanceDelta;
import warmachinesystem.TBFieldAllowanceRelativeDelta;
import warmachinesystem.TBFreeUnit;
import warmachinesystem.TBInGameRule;
import warmachinesystem.TBPointCostDelta;
import warmachinesystem.TierBenefit;
import warmachinesystem.TierLevel;
import warmachinesystem.TierLevelType;
import warmachinesystem.TierList;
import warmachinesystem.TierRequirement;
import warmachinesystem.UnitAttachment;
import warmachinesystem.Warcaster;

public class RosterTierCalculator {

	private Roster roster;
	
	private TierList tierList;
	
	private UnitCounter unitCounter;
	
	private TierStatus status;
	
	public RosterTierCalculator(Roster roster, UnitCounter unitCounter) {
		this.roster = roster;
		this.unitCounter = unitCounter;
	}

	protected Roster getRoster() {
		return roster;
	}

	public TierStatus calculateTier() {
		status = new TierStatus();
		updateTierList();
		validateTierLevel();
		return status;
	}

	private void updateTierList() {
		List<WarcasterRosterElement> warcasters = getRoster().getWarcasters();
		if (warcasters.size() == 1) {
			tierList = getRoster().getArmyList().getTierList(warcasters.get(0).getWarcaster());
		} else {
			tierList = null;
		}
		
	}




	protected void validateTierLevel() {
		TierLevelType tierLevelType = TierLevelType.NO_TIER;
		if (isTierElegible()){
			List<TierLevel> tierLevels = getTierLevels();
			for (TierLevel tl : tierLevels) {
				List<TierRequirement> requirements = tl.getRequirements();
				List<TierRequirement> unfulfilledRequirements = new ArrayList<TierRequirement>();
				for (TierRequirement tr : requirements) {
					if (!tr.isMet(unitCounter.getCount(), getRoster().getArmyList())) {
						unfulfilledRequirements.add(tr);
					}
				}
				if (unfulfilledRequirements.size() == 0) {
					tierLevelType = tl.getLevel();
				} else {
					break;
				}
			}
		}
		status.setCurrentTierLevel(tierLevelType);
		handleTierBenefits(getBenefits());
	}

	private boolean isTierElegible() {
		if (tierList == null){
			return false;
		}
		for (BaseUnit bu : unitCounter.getUnits()){
			if (!(bu instanceof Warcaster) && !(bu instanceof UnitAttachment ) && !tierList.getAllowedUnits().contains(bu)){
				return false;
			}
		}
		return true;
	}

	private void handleTierBenefits(List<TierBenefit> benefits) {
		
		for (TierBenefit tb : benefits) {
			if (tb instanceof TBFieldAllowanceRelativeDelta) {
				TBFieldAllowanceRelativeDelta tbfad = (TBFieldAllowanceRelativeDelta) tb;
				Integer referenceCount = unitCounter
						.getCount(tbfad.getReferenceUnit());
				if (referenceCount == null) referenceCount = 0;
				status.addUnitFaDelta(tbfad.getAffectedUnits(tierList.getWarcaster().getArmyList()), String.valueOf(referenceCount * Integer.parseInt(tbfad.getFieldAllowance())));
			} else if (tb instanceof TBFieldAllowanceDelta){
				TBFieldAllowanceDelta ad = (TBFieldAllowanceDelta) tb;
				status.addUnitFaDelta(ad.getAffectedUnits(tierList.getWarcaster().getArmyList()), ad.getFieldAllowance());
			} else if (tb instanceof TBFreeUnit){
				TBFreeUnit tbfu = (TBFreeUnit) tb;
				status.addFreeUnits(tbfu.getAffectedUnits(tierList.getWarcaster().getArmyList()), tbfu.getNumberUnit());
			} else if (tb instanceof TBInGameRule){
				TBInGameRule igr = (TBInGameRule) tb;
				status.addIngameRule(igr.getDescription());
			} else if (tb instanceof TBPointCostDelta){
				TBPointCostDelta tbpcd = (TBPointCostDelta) tb;
				status.addUnitCostDelta(tbpcd.getAffectedUnits(tierList.getWarcaster().getArmyList()), tbpcd.getPointCostDelta());
			}
		}
	}


	protected List<TierBenefit> getBenefits() {
		List<TierBenefit> tierBenefitList = new ArrayList<TierBenefit>();
		for (TierLevel tl : getTierLevels()) {
			if (tl.getLevel().compareTo(status.getCurrentTierLevel()) <= 0) {
				tierBenefitList.addAll(tl.getBenefits());
			}
		}

		return tierBenefitList;
	}

	private List<TierLevel> getTierLevels() {
		if (tierList == null) {
			return Collections.emptyList();
		}
		return tierList.getLevels();
	}
	
}
